package avl.sv.client;

import avl.sv.client.source.SlideSourcePort;
import avl.sv.client.source.SolutionSourcePort;
import avl.sv.server.slides.Slides;
import avl.sv.server.slides.Slides_Service;
import avl.sv.server.training.Training;
import avl.sv.server.training.Training_Service;
import avl.sv.shared.AVM_Properties;
import avl.sv.shared.Permissions;
import avl.sv.shared.SlideReference;
import avl.sv.shared.SlideSet;
import avl.sv.shared.SlideSets;
import avl.sv.shared.XML.SlideSetsXML_Parser;
import avl.sv.shared.fileFilters.SlideFilter;
import avl.sv.shared.sources.SlideSource;
import avl.sv.shared.sources.SlideSourceFile;
import avl.sv.shared.sources.SolutionSource;
import com.sun.xml.ws.client.BindingProviderProperties;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.MessageContext;


public class AdvancedVirtualMicroscope extends javax.swing.JFrame {
    private static Slides slidesPort;
    private static Training trainingPort;
    private static JFileChooser jFileChooserLocalSlide;
    private static final SolutionManager solutionManager = new SolutionManager();
    private static long solutionsListVersion = 0;
    private static URL slidesPortLocaion = null, trainingPortLocation = null;
    private static LoginDialog loginDialog;
    private static UploadSlideFrame uploadSlideFrame;
    private static final ScheduledExecutorService worker = Executors.newScheduledThreadPool(5);
    private static final int STATUS_MESSAGE_TIMEOUT = 5000;
    private static Log logFrame = new Log();
    private static final String TITLE_STRING = "Advanced Virtual Microscope";
    private static Timer statusTimer = new Timer(STATUS_MESSAGE_TIMEOUT, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            jTextField1.setText("running");
        }
    });
    
    public static void main(final String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(AdvancedVirtualMicroscope.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                AdvancedVirtualMicroscope avm = AdvancedVirtualMicroscope.getInstance();
                Dimension d = avm.getPreferredSize();
                avm.setSize(d);
                avm.pack();
                avm.setVisible(true);
                for (int i = 0; i < args.length; i++) {
                    switch (args[i]) {
                        case "-server":
                            if ((i + 1) < args.length) {
                                try {
                                    AdvancedVirtualMicroscope.setServerURL(new URL(args[i + 1]));
                                } catch (MalformedURLException ex) {
                                    Logger.getLogger(AdvancedVirtualMicroscope.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                            break;
                    }
                }
            }
        });
    }
    
    static void showLogWindow() {
        logFrame.setVisible(true);
    }
    
    private static AdvancedVirtualMicroscope instance = null;
    public static AdvancedVirtualMicroscope getInstance(){
        if (instance == null){
            instance = new AdvancedVirtualMicroscope();
        }
        return instance;
    }
    private AdvancedVirtualMicroscope() {
        initComponents();
        setupLookAndFeel();
        loginDialog = new LoginDialog(this);

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
//              // Add a loading note
                DefaultMutableTreeNode loadingNode = new DefaultMutableTreeNode();
                loadingNode.add(new DefaultMutableTreeNode("Loading data from server..."));
                jTreeSlides.setModel(new DefaultTreeModel(loadingNode));
                jTreeSolution.setModel(new DefaultTreeModel(loadingNode));

                setupLookAndFeel();

                worker.scheduleAtFixedRate(new Runnable() {
                    @Override
                    public void run() {
                        if (slidesPort == null) {
                            slidesPort = initSlidesPort();
                            updateSlideSetTree();
                        } 
                    }
                }, 1, 3, TimeUnit.SECONDS);  
                
                worker.scheduleAtFixedRate( new Runnable() {
                    @Override
                    public void run() {
                        if (trainingPort == null) {
                            trainingPort = initTrainingPort();
                            solutionManager.pack();
                        } else {
                            try {
                                String result = trainingPort.keepAlive();
                                if (result == null || result.contains("user session expired")){
                                    trainingPort = null;
                                    setStatusText("Error when contacting training server, will attempt re-login, " + result, 9 * 1000);  
                                } else if (result.isEmpty() || result.contains("error:")){
                                    setStatusText("Error when contacting training server. " + result, 10 * 1000);        
                                }
                            } catch (WebServiceException ex){ 
                            }
                        }
                    }
                }, 1, 10, TimeUnit.SECONDS);
                
                worker.scheduleAtFixedRate(new Runnable() {
                    @Override
                    public void run() {
                        if (jTabbedPane.getSelectedIndex() == 0) {
                            updateSolutionsTree();
                        }
                    }
                }, 2, 3, TimeUnit.SECONDS);
                
                worker.scheduleAtFixedRate(new Runnable() {
                    @Override
                    public void run() {
                        if (jTabbedPane.getSelectedIndex() == 0) {
                            studyManager.populateStudiesComboBox();
                        }
                    }
                }, 3, 3, TimeUnit.SECONDS);
                
            }
        });

        uploadSlideFrame = new UploadSlideFrame(this);
        
        jFileChooserLocalSlide = new JFileChooser();
        jFileChooserLocalSlide.setFileFilter(new SlideFilter());
    }
    
    private static void setServerURL(URL serverURL) throws MalformedURLException {
        String host = serverURL.getHost();
        trainingPortLocation = new URL("https://" + host + ":443/AVM_Server/Training?wsdl");
        slidesPortLocaion    = new URL("http://"  + host + ":80/AVM_Server/Slides?wsdl");     
    }

    public static SlideViewer getSelectedSlideviewer() {
        Component comp = jTabbedPane.getSelectedComponent();
        if (comp instanceof SlideViewer) {
            return (SlideViewer) comp;
        } else {
            return null;
        }
    }

    public static StudyManager getStudyManager() {
        return studyManager;
    }

    static SolutionManager getSolutionManager() {
        return solutionManager;
    }
    
    public static SlideSets getSlideSets(){
        String xml;
        try {
            xml = slidesPort.getSlideSets();
        } catch (WebServiceException ex){
            return null;
        }
        if (xml == null || xml.startsWith("error:")){
            DefaultMutableTreeNode errorNode = new DefaultMutableTreeNode("root");
            if (xml == null){
                errorNode.add(new DefaultMutableTreeNode(xml));
            } else {
                errorNode.add(new DefaultMutableTreeNode("Failed to get slide sets"));
            }
            jTreeSlides.setModel(new javax.swing.tree.DefaultTreeModel(errorNode));
            return null;
        }
        SlideSetsXML_Parser parser = new SlideSetsXML_Parser();
        SlideSets slideSets = parser.parse(xml);
        return slideSets;
    }
    
    public void updateSlideSetTree() {
        if (slidesPort == null) {
            return;
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                // populate slide list
                SlideSets slideSets = getSlideSets();
                if (slideSets == null){
                    return;
                }
                jTreeSlides.setModel(new javax.swing.tree.DefaultTreeModel(slideSets));
            }
        });
//        worker.schedule(new Runnable() {
//            @Override
//            public void run() {
//                updateSlideSetTree();                                
//            }
//        }, 5, TimeUnit.SECONDS);
    }

    public static void updateSolutionsTree() {
        if (trainingPort == null) {
            return;
        }
        if (jTabbedPane.getSelectedIndex() != 0) {
            return;
        }        
        long tempLong = trainingPort.getSolutionsListVersion();
        if (solutionsListVersion == tempLong) {
            return;
        }
        solutionsListVersion = tempLong;
        
        java.awt.EventQueue.invokeLater(new Runnable() {
            class SolutionRef {
                final public int id;
                final public String name;
                public SolutionRef(int id, String name) {
                    this.id = id;
                    this.name = name;
                }
            }
        
            @Override
            public void run() {
                String setRefs = trainingPort.getSolutionsList();
                ArrayList<SolutionSourcePort> solutionSources = new ArrayList<>();
                if (!setRefs.isEmpty()) {
                    for (final String pair:setRefs.split(";")){
                        final String temp[] = pair.split(",");
                        if (temp.length == 2){
                            String name = temp[1];
                            int id = Integer.valueOf(temp[0]);
                            SolutionSourcePort solutionSource = new SolutionSourcePort(trainingPort, name, id);
                            if (solutionSource.getVersion() < 0){
                                continue;
                            }
                            solutionSources.add(solutionSource);
                        }                        
                    }
                }
                
                Collections.sort(solutionSources, new Comparator<SolutionSourcePort>() {
                    @Override
                    public int compare(SolutionSourcePort o1, SolutionSourcePort o2) {
                        return o1.getName().compareTo(o2.getName());
                    }
                });
                
                DefaultMutableTreeNode topNode = new DefaultMutableTreeNode("Top");
                for (SolutionSource solutionSource:solutionSources) {
                    topNode.add(solutionSource);
                }
                jTreeSolution.setModel(new javax.swing.tree.DefaultTreeModel(topNode));
            }

        });
    }
    
    private Slides initSlidesPort(){
        Slides tempSlidesPort = null;
        try {
            Slides_Service ss = new Slides_Service(slidesPortLocaion);
            tempSlidesPort = ss.getSlidesPort();
            Map<String, Object> req_ctx = ((BindingProvider) tempSlidesPort).getRequestContext();
            req_ctx.put( BindingProviderProperties.CONNECT_TIMEOUT, 5000);
            req_ctx.put( BindingProviderProperties.REQUEST_TIMEOUT, 5000);
            req_ctx.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
            jButtonUploadImage.setEnabled(true);
        } catch (WebServiceException ex) {
            setStatusText("Failed to connect to slide server at: " + trainingPortLocation, 0);
        }
        return tempSlidesPort;
    }
    private Training initTrainingPort(){
        Training tempTrainingPort = null;
        try {
            if (loginDialog.isCanceled()){
                return null;
            }
            tempTrainingPort = getTempTrainingPort();
            String temp = tempTrainingPort.login(loginDialog.getUsername(), loginDialog.getPassword());
            if ((temp == null) || (temp.contains("error:"))){
                loginDialog.setVisible(true);
                if (loginDialog.getUsername().equals("") || loginDialog.isCanceled()) {
                    return null;
                }            
                temp = tempTrainingPort.login(loginDialog.getUsername(), loginDialog.getPassword());
                if (temp == null) {
                    setStatusText("Failed to login to training server at: " + trainingPortLocation, 0);
                    return null;
                }
                if (temp.contains("error:")) {
                    setStatusText("Failed to login to training server at: " + trainingPortLocation + "because " + temp, 0);
                    return null;
                } 
            }
            setTitle(TITLE_STRING+",    Logged in as " + loginDialog.getUsername());
            Map<String, Object> req_ctx = ((BindingProvider)tempTrainingPort).getRequestContext();
            Map<String, List<String>> headers = new HashMap<>();
            headers.put("SessionID", Collections.singletonList(temp));
            req_ctx.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
            req_ctx.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
            req_ctx.put( BindingProviderProperties.CONNECT_TIMEOUT, 5000);
            req_ctx.put( BindingProviderProperties.REQUEST_TIMEOUT, 50000);

            setStatusText("Logged into training server", 4*1000);
            studyManager.setEnabled(true);
            jButtonShowSolutionManager.setEnabled(true);
            
            repaint();
        } catch (WebServiceException ex) {
            setStatusText("Failed to connect to training server at: " + trainingPortLocation, 0);
        }
        return tempTrainingPort;
    }
    public static Training getTempTrainingPort(){
        Training_Service ts = new Training_Service(trainingPortLocation);
        return ts.getTrainingPort();
    }
    
    public static Training getTrainingPort() {
        return trainingPort;
    }
    public static Slides getSlidesPort() {
        return slidesPort;
    }
    
    public static void setStatusText(String status, int timeoutInMilliseconds) {
        statusTimer.stop();
        jTextField1.setText(status);
        System.out.println(status);
        if (timeoutInMilliseconds > 0){
            statusTimer.setDelay(timeoutInMilliseconds); 
            statusTimer.restart(); 
        }
        if (!status.endsWith("\n")){
            status += "\n";
        }
        logFrame.insert(status, 0);
    }

    public static SlideSource getSlideSource(SlideReference slide) {
        return new SlideSourcePort(slidesPort, slide);
    }

    public static void addSlideViewer(SlideSource slideSource) {
        SlideViewer slideViewer = new SlideViewer(slideSource);
        String title;
        if (slideSource.getSlideSetName() == null) {
            title = slideSource.getImageName();
        } else {
            title = slideSource.getSlideSetName() + "\\" + slideSource.getImageName();
        }
        jTabbedPane.addTab(title, slideViewer);

        // Resize panel
        Component mainPannel = jTabbedPane.getComponent(0);
        slideViewer.setSize(mainPannel.getSize().width, mainPannel.getSize().height);
        slideViewer.setLocation(mainPannel.getLocation());
        slideViewer.centerImage();
        jTabbedPane.setSelectedComponent(slideViewer);
        slideViewer.requestFocus();
    }

    private void setupLookAndFeel() {
        try {
            //javax.swing.UIManager.setLookAndFeel(new NimbusLookAndFeel());
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    SwingUtilities.updateComponentTreeUI(this);
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(AdvancedVirtualMicroscope.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

    }

    public static ArrayList<SlideViewer> getOpenSlideViewers() {
        ArrayList<SlideViewer> svList = new ArrayList<>();
        Component[] cs = jTabbedPane.getComponents();
        for (Component c : cs) {
            if (c instanceof SlideViewer) {
                svList.add((SlideViewer) c);
            }
        }
        return svList;
    }

    public static void setTopSlideViewer(SlideViewer sv) {
        if (sv == null) {
            return;
        }
        jTabbedPane.setSelectedComponent(sv);
    }

    private void closeSelectedTab() {
        if (jTabbedPane.getSelectedIndex() == 0) {
            return;
        }
        Component c = jTabbedPane.getSelectedComponent();
        if (c instanceof SlideViewer) {
            SlideViewer sv = (SlideViewer) c;
            jTabbedPane.remove(sv);
            sv.close();
        } else {
            jTabbedPane.remove(c);
        }
        System.gc();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPopupMenuSolution = new javax.swing.JPopupMenu();
        jPopupMenuSlide = new javax.swing.JPopupMenu();
        jMenuItemSlideDelete = new javax.swing.JMenuItem();
        jPopupMenuTab = new javax.swing.JPopupMenu();
        jMenuItemTabClose = new javax.swing.JMenuItem();
        jScrollPane1 = new javax.swing.JScrollPane();
        jScrollPane2 = new javax.swing.JScrollPane();
        jLabel2 = new javax.swing.JLabel();
        jButtonUploadImage = new javax.swing.JButton();
        jLabelStatus = new javax.swing.JLabel();
        jTextField1 = new javax.swing.JTextField();

        jPopupMenuSolution.setMaximumSize(new java.awt.Dimension(200, 200));
        jPopupMenuSolution.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
            public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
            }
            public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
            }
            public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
                jPopupMenuSolutionPopupMenuWillBecomeVisible(evt);
            }
        });

        jMenuItemSlideDelete.setText("Delete");
        jMenuItemSlideDelete.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemSlideDeleteActionPerformed(evt);
            }
        });
        jPopupMenuSlide.add(jMenuItemSlideDelete);

        jMenuItemTabClose.setText("Close");
        jMenuItemTabClose.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemTabCloseActionPerformed(evt);
            }
        });
        jPopupMenuTab.add(jMenuItemTabClose);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Advanced Virtual Microscope");

        jTabbedPane.setComponentPopupMenu(jPopupMenuTab);
        jTabbedPane.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTabbedPaneMouseClicked(evt);
            }
        });

        jPanelMain.addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentShown(java.awt.event.ComponentEvent evt) {
                jPanelMainComponentShown(evt);
            }
        });

        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("JTree");
        jTreeSlides.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        jTreeSlides.setComponentPopupMenu(jPopupMenuSlide);
        jTreeSlides.setRootVisible(false);
        jTreeSlides.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTreeSlidesMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(jTreeSlides);

        treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        jTreeSolution.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        jTreeSolution.setToolTipText("");
        jTreeSolution.setComponentPopupMenu(jPopupMenuSolution);
        jTreeSolution.setRootVisible(false);
        jTreeSolution.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTreeSolutionMouseClicked(evt);
            }
        });
        jScrollPane2.setViewportView(jTreeSolution);

        jButtonShowSolutionManager.setText("Solution Manager");
        jButtonShowSolutionManager.setEnabled(false);
        jButtonShowSolutionManager.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonShowSolutionManagerActionPerformed(evt);
            }
        });

        jLabel1.setText("Slides");

        jLabel2.setText("Solutions");

        jButtonOpenSlide.setText("Open local image");
        jButtonOpenSlide.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonOpenSlideActionPerformed(evt);
            }
        });

        studyManager.setBorder(null);
        studyManager.setEnabled(false);

        jButtonUploadImage.setText("Upload image");
        jButtonUploadImage.setEnabled(false);
        jButtonUploadImage.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonUploadImageActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanelMainLayout = new javax.swing.GroupLayout(jPanelMain);
        jPanelMain.setLayout(jPanelMainLayout);
        jPanelMainLayout.setHorizontalGroup(
            jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelMainLayout.createSequentialGroup()
                .addGroup(jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE)
                    .addGroup(jPanelMainLayout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addGroup(jPanelMainLayout.createSequentialGroup()
                        .addComponent(jButtonOpenSlide, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButtonUploadImage, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane2)
                    .addGroup(jPanelMainLayout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addComponent(jButtonShowSolutionManager, javax.swing.GroupLayout.DEFAULT_SIZE, 251, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(studyManager, javax.swing.GroupLayout.DEFAULT_SIZE, 164, Short.MAX_VALUE))
        );
        jPanelMainLayout.setVerticalGroup(
            jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelMainLayout.createSequentialGroup()
                .addGroup(jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButtonShowSolutionManager)
                    .addComponent(jButtonOpenSlide)
                    .addComponent(jButtonUploadImage))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1)
                    .addComponent(jScrollPane2)))
            .addComponent(studyManager, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
        );

        jTabbedPane.addTab("Main", jPanelMain);

        jLabelStatus.setText("status:");
        jLabelStatus.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jLabelStatusMouseClicked(evt);
            }
        });

        jTextField1.setEditable(false);
        jTextField1.setText("running");
        jTextField1.setMinimumSize(new java.awt.Dimension(8, 20));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jLabelStatus)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(jTabbedPane)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabelStatus)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jTreeSlidesMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTreeSlidesMouseClicked
        if (evt.getClickCount() != 2) {
            return;
        }
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTreeSlides.getLastSelectedPathComponent();
        if (node == null) {
            return;
        }
        SlideReference sn;
        if (node instanceof SlideReference) {
            sn = (SlideReference) node;
        } else {
            return;
        }
        SlideSource slideSource = new SlideSourcePort(slidesPort, sn);
        addSlideViewer(slideSource);
    }//GEN-LAST:event_jTreeSlidesMouseClicked

    private void jTreeSolutionMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTreeSolutionMouseClicked
        if (evt.getClickCount() != 2) {
            return;
        }
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTreeSolution.getLastSelectedPathComponent();
        if (node == null) {
            return;
        }
        if (node instanceof SolutionSourcePort) {
            SolutionSourcePort csr = (SolutionSourcePort) node;
            solutionManager.setSolutionSource(csr);
            solutionManager.setVisible(true);
        }
    }//GEN-LAST:event_jTreeSolutionMouseClicked

    private void jButtonShowSolutionManagerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonShowSolutionManagerActionPerformed
        solutionManager.setVisible(true);
    }//GEN-LAST:event_jButtonShowSolutionManagerActionPerformed

    private void jButtonOpenSlideActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOpenSlideActionPerformed
        try {
            int result = jFileChooserLocalSlide.showDialog(this, "Open");
            if (result == JFileChooser.CANCEL_OPTION){
                return;
            }
            File f = jFileChooserLocalSlide.getSelectedFile();
            if (f == null) {
                return;
            }
            SlideSource slideSource = new SlideSourceFile(f);
            addSlideViewer(slideSource);
        } catch (IOException ex) {
            Logger.getLogger(AdvancedVirtualMicroscope.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_jButtonOpenSlideActionPerformed

    private void jPanelMainComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_jPanelMainComponentShown

    }//GEN-LAST:event_jPanelMainComponentShown

    private void jTabbedPaneMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTabbedPaneMouseClicked
        if (evt.getButton() == MouseEvent.BUTTON2) {
            closeSelectedTab();
        }
    }//GEN-LAST:event_jTabbedPaneMouseClicked

    private void jPopupMenuSolutionPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_jPopupMenuSolutionPopupMenuWillBecomeVisible
        jPopupMenuSolution.removeAll();
        final Frame frame = this;
        final TreePath path = jTreeSolution.getSelectionPath();
        if (path == null){
            return;
        }
        Object obj = path.getLastPathComponent();
        if (obj instanceof SolutionSourcePort){
            final SolutionSourcePort ssp = (SolutionSourcePort) obj;
            String ps = trainingPort.getPermissionsSolution(ssp.getId(), null);
            Permissions p = Permissions.valueOf(ps);
            if (p.equals(Permissions.ADMIN)){
                JMenuItem item = new JMenuItem("Permissions");
                item.addActionListener(new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        new PermissionPrompt(frame, "solution", ssp.getId(), trainingPort ).setVisible(true);
                    }
                });
                jPopupMenuSolution.add(item);

                JMenuItem itemDelete = new JMenuItem("Delete");
                itemDelete.addActionListener(new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        String result = ssp.delete();
                        if (result.startsWith("error:")){
                            AdvancedVirtualMicroscope.setStatusText("Couldn not delete solution " + ssp.getName() +". " + result, 4*1000);
                        } else {
                            AdvancedVirtualMicroscope.setStatusText("Solution " + ssp.getName() + " was deleted", 4*1000);
                            if (solutionManager.solutionSource != null){
                                if (ssp.getId() == solutionManager.solutionSource.getId()){
                                    solutionManager.setSolutionSource(null);
                                   solutionManager.setVisible(false);
                                }                           
                            }
                        }
                    }
                });
                jPopupMenuSolution.add(itemDelete);
            }
        }
        if (jPopupMenuSolution.getComponentCount() == 0){
            jPopupMenuSolution.add("No options");
        }
        jPopupMenuSolution.pack();
    }//GEN-LAST:event_jPopupMenuSolutionPopupMenuWillBecomeVisible
    
    private void jButtonUploadImageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonUploadImageActionPerformed
        uploadSlideFrame.setVisible(true);
    }//GEN-LAST:event_jButtonUploadImageActionPerformed

    private void jMenuItemSlideDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemSlideDeleteActionPerformed
        TreePath path = jTreeSlides.getSelectionPath();
        DefaultTreeModel model = (DefaultTreeModel) jTreeSlides.getModel();
        if (path == null){
            return;
        }
        Object obj = path.getLastPathComponent();
        if (obj instanceof SlideReference){
            SlideReference slideReference = (SlideReference) obj;           
            String result = slidesPort.deleteSlide(slideReference.slideSetName, slideReference.slideName);
            if (result.startsWith("error:")){
            } else {
                model.removeNodeFromParent(slideReference);
                setStatusText(result, 1000*4);
            }
        }
        if (obj instanceof SlideSet){
            SlideSet slideSet = (SlideSet) obj;
            for (SlideReference slideReference:slideSet.getSlides()){
                String result = slidesPort.deleteSlide(slideReference.slideSetName, slideReference.slideName);
                if (result.startsWith("error:")){
                } else {
                    model.removeNodeFromParent(slideReference);
                    setStatusText(result, 1000*4);
                }
            }
            model.removeNodeFromParent(slideSet);
        }
    }//GEN-LAST:event_jMenuItemSlideDeleteActionPerformed

    private void jMenuItemTabCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemTabCloseActionPerformed
        closeSelectedTab();
    }//GEN-LAST:event_jMenuItemTabCloseActionPerformed

    private void jLabelStatusMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLabelStatusMouseClicked
        logFrame.setVisible(true);
    }//GEN-LAST:event_jLabelStatusMouseClicked
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private static final javax.swing.JButton jButtonOpenSlide = new javax.swing.JButton();
    private static final javax.swing.JButton jButtonShowSolutionManager = new javax.swing.JButton();
    private javax.swing.JButton jButtonUploadImage;
    private static final javax.swing.JLabel jLabel1 = new javax.swing.JLabel();
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabelStatus;
    private javax.swing.JMenuItem jMenuItemSlideDelete;
    private javax.swing.JMenuItem jMenuItemTabClose;
    private static final javax.swing.JPanel jPanelMain = new javax.swing.JPanel();
    private javax.swing.JPopupMenu jPopupMenuSlide;
    private javax.swing.JPopupMenu jPopupMenuSolution;
    private javax.swing.JPopupMenu jPopupMenuTab;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private static final javax.swing.JTabbedPane jTabbedPane = new javax.swing.JTabbedPane();
    private static javax.swing.JTextField jTextField1;
    private static final javax.swing.JTree jTreeSlides = new javax.swing.JTree();
    private static final javax.swing.JTree jTreeSolution = new javax.swing.JTree();
    private static final avl.sv.client.StudyManager studyManager = new avl.sv.client.StudyManager();
    // End of variables declaration//GEN-END:variables
}
